#ifndef _M_LOGGER_H
#define _M_LOGGER_H
#ifndef _GNU_SOURCE
#define _GNU_SOURCE // #include <sys/stat.h>//间接包含 _GNU_SOURCE 这个宏
#endif
#include "logsink.hpp"
#include <mutex>
#include <stdarg.h>
#include <unordered_map>
#include "looper.hpp"
class Logger
{

public:
  using lptr = std::shared_ptr<Logger>;

  Logger(std::string loggername,
         Level::LevelType limitlevel,
         Formatter ::fptr formatter,
         std::vector<Logsink::lptr> sinks) : _loggername(loggername),
                                             _limitlevel(limitlevel),
                                             _formatter(formatter),
                                             _sinks(sinks.begin(), sinks.end())
  {
  }
  void Debug(const std::string &file, size_t line, const std::string &fmt, ...)
  {
    if (Level::LevelType::DEBUG < _limitlevel)
    {
      return;
    } // 小于当前等级不进行输出日志
    // 把用户输入的不定参数据格式化出来

    va_list ap;
    va_start(ap, fmt); // 让ap指针指向fmt的下一个位置
    char *res;
    int ret = vasprintf(&res, fmt.c_str(), ap);
    if (ret == -1)
    {
      std::cout << "va格式化失败\n";
      return;
    }
    va_end(ap); // 把ap指针置空
    // 进行日志信息msg转化：
    Logmsg msg(_loggername, file, line, Level::LevelType::DEBUG, res);
    // 日志格式化：
    std::string formatmsg = _formatter->Format(msg);
    // 日志落地处理：
    Log(formatmsg.c_str(), formatmsg.size());
    free(res); // 及时释放防止内存泄漏
  }
  void Info(const std::string &file, size_t line, const std::string &fmt, ...)
  {
    if (Level::LevelType::INFO < _limitlevel)
    {
      return;
    } // 小于当前等级不进行输出日志
    // 把用户输入的不定参数据格式化出来

    va_list ap;
    va_start(ap, fmt); // 让ap指针指向fmt的下一个位置
    char *res;
    int ret = vasprintf(&res, fmt.c_str(), ap);
    if (ret == -1)
    {
      std::cout << "va格式化失败\n";
      return;
    }
    va_end(ap);
    // 进行日志信息msg转化：
    Logmsg msg(_loggername, file, line, Level::LevelType::INFO, res);
    // 日志格式化：
    std::string formatmsg = _formatter->Format(msg);
    // 日志落地处理：
    Log(formatmsg.c_str(), formatmsg.size());
    free(res); // 及时释放防止内存泄漏
  }
  void Warn(const std::string &file, size_t line, const std::string &fmt, ...)
  {

    if (Level::LevelType::WARN < _limitlevel)
    {
      return;
    } // 小于当前等级不进行输出日志
    // 把用户输入的不定参数据格式化出来

    va_list ap;
    va_start(ap, fmt); // 让ap指针指向fmt的下一个位置
    char *res;
    int ret = vasprintf(&res, fmt.c_str(), ap);
    if (ret == -1)
    {
      std::cout << "va格式化失败\n";
      return;
    }
    va_end(ap);

    // 进行日志信息msg转化：
    Logmsg msg(_loggername, file, line, Level::LevelType::WARN, res);
    // 日志格式化：
    std::string formatmsg = _formatter->Format(msg);
    // 日志落地处理：
    Log(formatmsg.c_str(), formatmsg.size());
    free(res); // 及时释放防止内存泄漏
  }
  void Error(const std::string &file, size_t line, const std::string &fmt, ...)
  {
    if (Level::LevelType::ERROR < _limitlevel)
    {
      return;
    } // 小于当前等级不进行输出日志
    // 把用户输入的不定参数据格式化出来

    va_list ap;
    va_start(ap, fmt); // 让ap指针指向fmt的下一个位置
    char *res;
    int ret = vasprintf(&res, fmt.c_str(), ap);
    if (ret == -1)
    {
      std::cout << "va格式化失败\n";
      return;
    }
    va_end(ap);

    // 进行日志信息msg转化：
    Logmsg msg(_loggername, file, line, Level::LevelType::ERROR, res);
    // 日志格式化：
    std::string formatmsg = _formatter->Format(msg);
    // 日志落地处理：
    Log(formatmsg.c_str(), formatmsg.size());
    free(res); // 及时释放防止内存泄漏
  }
  void Fatal(const std::string &file, size_t line, const std::string &fmt, ...)
  {

    if (Level::LevelType::FATAL < _limitlevel)
    {
      return;
    } // 小于当前等级不进行输出日志
    // 把用户输入的不定参数据格式化出来

    va_list ap;
    va_start(ap, fmt); // 让ap指针指向fmt的下一个位置
    char *res;
    int ret = vasprintf(&res, fmt.c_str(), ap);
    if (ret == -1)
    {
      std::cout << "va格式化失败\n";
      return;
    }
    va_end(ap);

    // 进行日志信息msg转化：
    Logmsg msg(_loggername, file, line, Level::LevelType::FATAL, res);
    // 日志格式化：
    std::string formatmsg = _formatter->Format(msg);
    // 日志落地处理：
    Log(formatmsg.c_str(), formatmsg.size());
    free(res); // 及时释放防止内存泄漏
  }

  virtual void Log(const char *data, size_t len) = 0;

protected:
  std::mutex _mutex;
  std::string _loggername;           // 传入的日志器名称
  Level::LevelType _limitlevel;      // 当前限制的日志等级标准（大于它的才能进行输出）
  Formatter ::fptr _formatter;       // 日志格式化器
  std::vector<Logsink::lptr> _sinks; // 日志落地器数组
};

class Synclogger : public Logger
{

public:
  Synclogger(std::string loggername,
             Level::LevelType limitlevel,
             Formatter ::fptr formatter,
             std::vector<Logsink::lptr> sinks) : Logger(loggername, limitlevel, formatter, sinks) {}

  void Log(const char *data, size_t len) override
  {
    if (_sinks.empty())
    {
      return;
    }
    // 防止多线程同时对sinks读写操作 这里加个智能锁；
    std::unique_lock<std::mutex> lock(_mutex);
    for (auto &it : _sinks)
    {
      it->log(data, len);
    }
  }
};

class Asynclogger : public Logger
{

public:
  Asynclogger(std::string loggername,
              Level::LevelType limitlevel,
              Formatter ::fptr formatter,
              std::vector<Logsink::lptr> sinks,
              AsyncIsSafe issafe) : Logger(loggername, limitlevel, formatter, sinks),
                                    _alooper(std::make_shared<Asynclooper>(std::bind(&Asynclogger::realcb, this, std::placeholders::_1), issafe)) {}
  // 这里bind绑定后的新函数是个纯右值，并能被左值引用！
  void Log(const char *data, size_t len) override
  {
    _alooper->Push(data, len);
  }
  // 默认realcb有this指针必须绑定一下
  void realcb(Buffer &bf)
  {
    if (_sinks.empty())
    {
      return;
    }

    for (auto &it : _sinks)

    {
      // 这里不想同步日志器输出一样加锁，因为调用它的线程必定只有一个（在一个双缓冲区下）
      it->log(bf.R_begin(), bf.Rd_size());
    }
  }

private:
  std::shared_ptr<Asynclooper> _alooper; // 异步缓冲区的管理者
};

enum class Loggertype
{

  LOGGER_SYNC,
  LOGGER_ASYNC

};

class Loggerbuilder
{

public:
  using ptr = std::shared_ptr<Loggerbuilder>;

  Loggerbuilder() : _loggertype(Loggertype::LOGGER_SYNC), _limitlevel(Level::LevelType::DEBUG) {}
  void Buildloggertype(Loggertype t)
  {
    _loggertype = t;
  }
  void Buildloggername(const std::string loggername)
  {
    _loggername = loggername;
  }
  void Buildlimitlevel(Level::LevelType limitlevel)
  {
    _limitlevel = limitlevel;
  }
  void Buildformmater(const std::string &pattern)
  {
    _formatter = std::make_shared<Formatter>(pattern);
  }
  void Buildloopertype(AsyncIsSafe safe)
  {
    _alooper_type = safe;
  }
  // 应对不同日志落地器的需求改成模版函数：
  template <typename sinktype, typename... Args>
  void Buildlogsinks(Args &&...args)
  {
    Logsink::lptr sink = std::make_shared<sinktype>(std::forward<Args>(args)...);
    _sinks.push_back(sink);
  }
  virtual Logger::lptr Build() = 0; // 提供一个不同类型的组装接口

protected: // 因为想让子类继承下来直接访问到它！
  Loggertype _loggertype;
  std::string _loggername;           // 传入的日志器名称
  Level::LevelType _limitlevel;      // 当前限制的日志等级标准（大于它的才能进行输出）
  Formatter ::fptr _formatter;       // 日志格式化器
  std::vector<Logsink::lptr> _sinks; // 日志落地器数组
  AsyncIsSafe _alooper_type;
};

// 供给loggermanage自己用

class Localloggerbuilder : public Loggerbuilder
{

public:
  // 这边基类的构造是无参无需显示调用

  Logger::lptr Build() override
  {
    assert(!_loggername.empty());
    if (_formatter.get() == nullptr)
    {
      _formatter = std::make_shared<Formatter>();
    }

    if (_sinks.empty())
    {
      Buildlogsinks<Stdoutsink>(); // 直接调用封装的零部件接口即可
    }

    if (_loggertype == Loggertype::LOGGER_ASYNC)
    {
      // return Logger::lptr();//暂时先这么处理
      return std::make_shared<Asynclogger>(_loggername, _limitlevel, _formatter, _sinks, _alooper_type);
    }

    else
    {
      // LOGGER_SYNC：同步日志器
      return std::make_shared<Synclogger>(_loggername, _limitlevel, _formatter, _sinks);
    }
  }
};

// 单例的一个类提供所有日志器的管理   懒汉模式
class Loggermanager
{

public:
  static Loggermanager &Getinstance()
  {
    static Loggermanager lr;
    return lr;
  }
  void Addlogger(const std::string name, Logger::lptr logger)
  {
    //std::unique_lock<std::mutex> lock(_mutex); 不能在这加否则出现死锁问题
     
    if (!Loggerisexit(name))
    {
    std::unique_lock<std::mutex> lock(_mutex);
      _map_loggers.insert({name, logger});
    }

  }

  bool Loggerisexit(const std::string name)
  {
    std::unique_lock<std::mutex> lock(_mutex);
    auto it = _map_loggers.find(name);
    if (it == _map_loggers.end())
    {
      return false;
    }
    return true;
  }

  Logger::lptr Getlogger(const std::string name)
  {
    std::unique_lock<std::mutex> lock(_mutex);
    if (_map_loggers.find(name) == _map_loggers.end())
      return Logger::lptr();
    return _map_loggers[name];
  }

  Logger::lptr &Getroot()
  {
    std::unique_lock<std::mutex> lock(_mutex);
    return _root_logger;
  }

private:
  // 初始化已经是线程安全的了：
  Loggermanager()

  {
    // 这个localbuilder只能被manager自己调用，外界添加就是用global,防止出现死循环问题：
    Loggerbuilder::ptr lr = std::make_shared<Localloggerbuilder>();

    lr->Buildloggername("root");
    Logger::lptr logger = lr->Build();
    // Addlogger("root",logger);
    _root_logger=logger;
    _map_loggers["root"] = logger; // 在这里手动添加
  }
  ~Loggermanager() {}

  Loggermanager(const Loggermanager &) = delete;
  Loggermanager &operator=(const Loggermanager &) = delete;

  std::mutex _mutex;
  Logger::lptr _root_logger; // 用户不注册时候默认的日志器
  std::unordered_map<std::string, Logger::lptr> _map_loggers;
};

class Globalloggerbuilder : public Loggerbuilder
{

public:
  // 这边基类的构造是无参无需显示调用

  Logger::lptr Build() override
  {

    assert(!_loggername.empty());
    if (_formatter.get() == nullptr)
    {
      //std::cout << "当前日志器：" << _loggername << " 未检测到日志格式，默认设置为[ %d{%H:%M:%S}%T%t%T[%p]%T[%c]%T%f:%l%T%m%n ]!\n";
      _formatter = std::make_shared<Formatter>();
    }

    if (_sinks.empty())
    {
      //std::cout << "当前日志器：" << _loggername << " 未检测到落地方向，默认设置为标准输出!\n";
      Buildlogsinks<Stdoutsink>(); // 直接调用封装的零部件接口即可
    }
    Logger::lptr lr;

    if (_loggertype == Loggertype::LOGGER_ASYNC)
    {
      // return Logger::lptr();//暂时先这么处理
      lr = std::make_shared<Asynclogger>(_loggername, _limitlevel, _formatter, _sinks, _alooper_type);
    }

    else
    {
      // LOGGER_SYNC：同步日志器
      lr = std::make_shared<Synclogger>(_loggername, _limitlevel, _formatter, _sinks);
    }

    Loggermanager::Getinstance().Addlogger(_loggername, lr);
    return lr;
  }
};
#endif
